#ifndef _COMMON_H_
#define _COMMON_H_

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <string.h>
#include <string>
#include <sstream>
#include <iostream>
#include <vector>

#define BUF_SIZE 2048
#define MY_PORT 1234

template <class T>
std::string itos(T i) {
    std::string s;
    std::stringstream out;
    out << i;
    s = out.str();    
    return s;
}

//////
struct Serializable {    
    virtual std::string   serialize () = 0;
    virtual bool          deserialize (std::string const& s) = 0;
    virtual void execute() 
    {}
};

struct A : Serializable {
    A () 
    {}

    A (size_t c1, size_t c2)
        : c1(c1), c2(c2)
    {}

    std::string  serialize () {
        std::string result("A");
        result += itos(c1) + " " + itos(c2);
        return result;
    }

    bool deserialize (std::string const& s) {
        if (s[0] == 'A') {
            std::stringstream ss;
            ss.str(s);
            char ch;
            size_t d1;
            size_t d2;
            ss >> ch >> d1 >> d2;
            own_vector.push_back(new A(d1, d2));        
            return true;
        }
        return false;
    }

    size_t get_data() {
        return c1 * c2;
    }

    static std::vector<A*> own_vector;
private:
    size_t c1;
    size_t c2;
};

std::vector<A*> A::own_vector;


struct B : Serializable {
    B ()
    {}

    B (int i)
        : i(i)
    {}

    std::string  serialize () {
        std::string result("B");
        result += itos(i);
        return result;
    }

    bool deserialize (std::string const& s) {
        if (s[0] == 'B') {
            std::stringstream ss;
            ss.str(s);
            char ch;
            int d;            
            ss >> ch >> d;
            own_vector.push_back(new B(d));            
            return true;
        }
        return false;
    }

    int get_data() {
        return i;
    }

    static std::vector<B*> own_vector;
private:
    int i;
};

std::vector<B*> B::own_vector;

struct C : Serializable {
    C ()
    {}

    C (float f)
        : f(f)
    {}

    std::string  serialize () {
        std::string result("C");
        result += itos(f);
        return result;
    }

    bool deserialize (std::string const& s) {
        if (s[0] == 'C') {
            std::stringstream ss;
            ss.str(s);
            char ch;
            float d;
            ss >> ch >> d;
            own_vector.push_back(new C(d));            
            return true;
        }
        return false;
    }

    float get_data() {
        return f;
    }

    void execute () {
        std::cout << "Hey, I'm executable!" << std::endl;
    }

    static std::vector<C*> own_vector;
private:
    float f;
};

std::vector<C*> C::own_vector;

struct BaseConsumer {
    virtual void action() = 0; 
    virtual bool deserialize(std::string const& s) = 0;
};

template <class T>
struct Consumer : BaseConsumer {

    Consumer()
        : prototype(new T()) {
        
    }    

    virtual ~Consumer() {
        for (size_t i = 0; i != T::own_vector.size(); ++i) {
            delete (T::own_vector[i]);
        }
        delete prototype;
    }

    bool deserialize(std::string const& s) {
        return prototype->deserialize(s);
    }

/*
    bool consume (std::string const& s) {
        T* object = (T*)(prototype->deserialize(s));
        if (object != NULL) {
            products.push_back(object);
            return true;
        }
        return false;
    }    
*/

    void action() {        
        for (size_t i = 0; i != T::own_vector.size(); ++i) {
            T::own_vector[i]->execute();
            std::cout << T::own_vector[i]->get_data() << std::endl;
            delete (T::own_vector[i]);
        }
        T::own_vector.clear();
    }
    
private:
    T* prototype;
};


struct ConsumerA : Consumer<A> {    
};

struct ConsumerB : Consumer<B> {    
};

struct ConsumerC : Consumer<C> {
};


#endif
